/*
自动绑定节点或组件
*/
const { ccclass, property, menu } = cc._decorator;

type NodeHandler = (
  instance: cc.Component,
  node: cc.Node,
  name: string
) => void;

// 节点前缀规则配置
const PREFIX = {
  BUTTON: ["btn", "button"],
  LABEL: ["lab", "lbl", "txt"],
  SPRITE: ["spr", "img", "texture", "sprite"],
  PROGRESS: ["progress"],
  EDIT: ["edit", "input"],
  SKELETON: ["skeleton", "spine"],
  SCROLLVIEW: ["list", "scroll"],
  PAGEVIEW: ["page", "pageView"],
  LAYOUT: ["layout"],
  TOOGLECONTAINER: ["togC"],
  TOOGLE: ["tog", "toggle"],
};
// 节点处理器映射表
const handlers = [
  { prefixes: PREFIX.BUTTON, handler: handleButton },
  { prefixes: PREFIX.LABEL, handler: handleLabel },
  { prefixes: PREFIX.SPRITE, handler: handleSprite },
  { prefixes: PREFIX.PROGRESS, handler: handleProgressBar },
  { prefixes: PREFIX.EDIT, handler: handleEditBox },
  { prefixes: PREFIX.SKELETON, handler: handleSkeleton },
  { prefixes: PREFIX.SCROLLVIEW, handler: handleScrollView },
  { prefixes: PREFIX.PAGEVIEW, handler: handlePageView },
  { prefixes: PREFIX.LAYOUT, handler: handleLayout },
  { prefixes: PREFIX.TOOGLECONTAINER, handler: handleToggleContainer },
  { prefixes: PREFIX.TOOGLE, handler: handleToggle },
];

// 注册按钮
function handleButton(
  instance: AutoBindComponent,
  node: cc.Node,
  name: string
): void {
  instance[name] = node.getComponent(cc.Button);
  if (instance[name]) instance.addClick(node);
}

// 注册文本
function handleLabel(
  instance: AutoBindComponent,
  node: cc.Node,
  name: string
): void {
  instance[name] = node.getComponent(cc.Label);
}

//注册图片
function handleSprite(
  instance: AutoBindComponent,
  node: cc.Node,
  name: string
): void {
  instance[name] = node.getComponent(cc.Sprite);
}

//注册进度条
function handleProgressBar(
  instance: AutoBindComponent,
  node: cc.Node,
  name: string
): void {
  instance[name] = node.getComponent(cc.ProgressBar);
}

//注册输入框
function handleEditBox(
  instance: AutoBindComponent,
  node: cc.Node,
  name: string
): void {
  instance[name] = node.getComponent(cc.EditBox);
  if (instance[name]) instance.addInputEndEvents(node);
}

//注册骨骼动画
function handleSkeleton(
  instance: AutoBindComponent,
  node: cc.Node,
  name: string
): void {
  instance[name] = node.getComponent(sp.Skeleton);
}

//注册滚动列表
function handleScrollView(
  instance: AutoBindComponent,
  node: cc.Node,
  name: string
): void {
  instance[name] = node.getComponent(cc.ScrollView);
}

//注册页面视图
function handlePageView(
  instance: AutoBindComponent,
  node: cc.Node,
  name: string
): void {
  instance[name] = node.getComponent(cc.PageView);
}

// 注册布局
function handleLayout(
  instance: AutoBindComponent,
  node: cc.Node,
  name: string
): void {
  instance[name] = node.getComponent(cc.Layout);
}

// 注册切换
function handleToggleContainer(
  instance: AutoBindComponent,
  node: cc.Node,
  name: string
): void {
  instance[name] = node.getComponent(cc.ToggleContainer);
  if (instance[name]) instance.addCheckEvents(node);
}

//注册单选
function handleToggle(
  instance: AutoBindComponent,
  node: cc.Node,
  name: string
): void {
  instance[name] = node.getComponent(cc.Toggle);
  if (instance[name]) instance.addToggleEvents(node);
}

//============================抽象类：自动绑定节点=============================
@ccclass
@menu("通用组件/自动绑定节点/AutoBindComponent")
export default abstract class AutoBindComponent extends cc.Component {
  private static NodeHandlers: Map<string, NodeHandler> = new Map();
  constructor() {
    super();
    if (!AutoBindComponent.NodeHandlers.size) {
      AutoBindComponent.initNodeHandlers(); // 确保只初始化一次
    }
    this.inject();
  }
  // 初始化处理器
  protected static initNodeHandlers(): void {
    if (!this.NodeHandlers.size) {
      handlers.forEach(({ prefixes, handler }) => {
        prefixes.forEach((prefix) => {
          this.registerNodeType(prefix, handler);
        });
      });
    }
  }

  public static registerNodeType(prefix: string, handler: NodeHandler): void {
    this.NodeHandlers.set(prefix, handler);
  }

  // 注入 onLoad / onDestroy
  protected inject(): void {
    const oldOnLoad = this.onLoad;
    this.onLoad = () => {
      this.autoMapping(this.node);
      if (oldOnLoad) oldOnLoad.call(this);
    };

    const oldOnDestroy = this.onDestroy;
    this.onDestroy = () => {
      if (oldOnDestroy) oldOnDestroy.call(this);
    };
  }

  // 自动映射节点
  protected autoMapping(node: cc.Node): void {
    const info = node.name.split("_");
    if (info.length > 1) {
      const prefix = info[0];
      const name = node.name;
      const handler = AutoBindComponent.NodeHandlers.get(prefix);

      if (handler) {
        handler(this, node, name);
      } else {
        this[name] = node;
      }
    } else {
      if (!(this as any)[node.name]) {
        (this as any)[node.name] = node;
      }
    }

    node.children.forEach((child) => this.autoMapping(child));
  }

  //给所有按钮节点添加Button组件
  addClick(node: cc.Node, onClickFunName: string = null, data: any = null) {
    var eventHandler = new cc.Component.EventHandler();
    eventHandler.target = this.node;
    //获取当前脚本组件
    eventHandler.component = cc.js.getClassName(this);
    eventHandler.handler = onClickFunName || "onBtnClick";
    eventHandler.customEventData = data || node.name;
    var clickEvents = node.getComponent(cc.Button).clickEvents;
    clickEvents.length = 0;
    clickEvents.push(eventHandler);
  }

  //给单选按钮添加点击事件
  addCheckEvents(node: cc.Node, onClickFunName?: string, data?: any) {
    var eventHandler = new cc.Component.EventHandler();
    eventHandler.target = this.node;
    //获取当前脚本组件
    eventHandler.component = cc.js.getClassName(this);
    eventHandler.handler = onClickFunName || "onToggleContainerClick";
    eventHandler.customEventData = data || node.name;
    var checkEvents = node.getComponent(cc.ToggleContainer).checkEvents;
    checkEvents.length = 0;
    checkEvents.push(eventHandler);
  }

  //给复选按钮添加点击事件
  addToggleEvents(node: cc.Node, onClickFunName?: string, data?: string) {
    var eventHandler = new cc.Component.EventHandler();
    eventHandler.target = this.node;
    //获取当前脚本组件
    eventHandler.component = cc.js.getClassName(this);
    eventHandler.handler = onClickFunName || "onToggleClick";
    eventHandler.customEventData = data || node.name;
    var checkEvents = node.getComponent(cc.Toggle).checkEvents;
    checkEvents.length = 0;
    checkEvents.push(eventHandler);
  }

  //添加输入框结束事件
  addInputEndEvents(node: cc.Node, onClickFunName?: string, data?: string) {
    var eventHandler = new cc.Component.EventHandler();
    eventHandler.target = this.node;
    //获取当前脚本组件
    eventHandler.component = cc.js.getClassName(this);
    eventHandler.handler = onClickFunName || "onEditBoxEnd";
    eventHandler.customEventData = data || node.name;
    var checkEvents = node.getComponent(cc.EditBox).editingDidEnded;
    checkEvents.length = 0;
    checkEvents.push(eventHandler);
  }

  protected onDestroy() {
    // 清理所有自动绑定的事件
    for (let key in this) {
      const comp = this[key] as any;
      //if (!comp || !comp instanceof cc.Component) continue;

      if (comp instanceof cc.Button) {
        comp.clickEvents.length = 0;
      } else if (comp instanceof cc.Toggle) {
        comp.checkEvents.length = 0;
      } else if (comp instanceof cc.ToggleContainer) {
        comp.checkEvents.length = 0;
      } else if (comp instanceof cc.EditBox) {
        comp.editingDidEnded.length = 0;
      }
    }

    // 调用用户自定义的 onDestroy
    const oldOnDestroy = this.onDestroy as any;
    if (oldOnDestroy && oldOnDestroy !== this.onDestroy) {
      oldOnDestroy.call(this);
    }
  }
}
